/**
 * 自动Git更新脚本
 * 检查Git仓库是否有更新，如果有则自动拉取并重启PM2进程
 */

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

// 设置工作目录到项目根目录
const projectRoot = path.join(__dirname, '..');
process.chdir(projectRoot);

const logger = require(path.join(projectRoot, 'src/utils/logger'));

class AutoUpdater {
  constructor() {
    this.updateLogFile = path.join(projectRoot, 'logs/auto-update.log');
    this.lockFile = path.join(projectRoot, 'logs/update.lock');
    this.ensureLogDir();
  }

  ensureLogDir() {
    const logDir = path.dirname(this.updateLogFile);
    if (!fs.existsSync(logDir)) {
      fs.mkdirSync(logDir, { recursive: true });
    }
  }

  async runCommand(command, description) {
    return new Promise((resolve, reject) => {
      this.log(`执行: ${command}`);
      
      exec(command, { timeout: 30000 }, (error, stdout, stderr) => {
        if (error) {
          this.log(`❌ ${description}失败: ${error.message}`, 'error');
          reject(error);
          return;
        }
        
        if (stderr && !stderr.includes('warning')) {
          this.log(`⚠️  ${description}警告: ${stderr}`, 'warn');
        }
        
        if (stdout) {
          this.log(`✅ ${description}成功: ${stdout.trim()}`);
        }
        
        resolve(stdout.trim());
      });
    });
  }

  log(message, level = 'info') {
    const timestamp = new Date().toISOString();
    const logMessage = `[${timestamp}] ${message}`;
    
    // 同时输出到控制台和文件
    console.log(logMessage);
    
    try {
      fs.appendFileSync(this.updateLogFile, logMessage + '\n');
    } catch (error) {
      console.error('写入日志文件失败:', error.message);
    }
  }

  checkLock() {
    if (fs.existsSync(this.lockFile)) {
      const lockContent = fs.readFileSync(this.lockFile, 'utf8');
      const lockTime = new Date(lockContent);
      const now = new Date();
      
      // 如果锁文件超过1小时，认为是异常锁，删除它
      if (now - lockTime > 60 * 60 * 1000) {
        this.log('发现过期的锁文件，删除并继续', 'warn');
        fs.unlinkSync(this.lockFile);
        return false;
      }
      
      this.log('检测到更新正在进行中，跳过本次检查');
      return true;
    }
    return false;
  }

  createLock() {
    fs.writeFileSync(this.lockFile, new Date().toISOString());
  }

  removeLock() {
    if (fs.existsSync(this.lockFile)) {
      fs.unlinkSync(this.lockFile);
    }
  }

  async checkGitStatus() {
    try {
      // 获取当前分支
      const currentBranch = await this.runCommand('git rev-parse --abbrev-ref HEAD', '获取当前分支');
      this.log(`当前分支: ${currentBranch}`);

      // 获取当前提交哈希
      const currentCommit = await this.runCommand('git rev-parse HEAD', '获取当前提交');
      this.log(`当前提交: ${currentCommit.substring(0, 8)}`);

      // 获取远程更新
      await this.runCommand('git fetch origin', '获取远程更新');

      // 检查是否有新的提交
      const remoteCommit = await this.runCommand(`git rev-parse origin/${currentBranch}`, '获取远程提交');
      
      if (currentCommit === remoteCommit) {
        this.log('📄 代码已是最新版本，无需更新');
        return false;
      }

      this.log(`🆕 发现新的更新: ${remoteCommit.substring(0, 8)}`);
      
      // 获取更新日志
      try {
        const updateLog = await this.runCommand(`git log --oneline ${currentCommit}..${remoteCommit}`, '获取更新日志');
        this.log(`更新内容:\n${updateLog}`);
      } catch (error) {
        this.log('获取更新日志失败，但继续更新流程', 'warn');
      }

      return true;
    } catch (error) {
      this.log(`Git状态检查失败: ${error.message}`, 'error');
      throw error;
    }
  }

  async pullUpdates() {
    try {
      // 拉取最新代码
      await this.runCommand('git pull origin', '拉取最新代码');
      
      // 检查package.json是否有变化
      const packageChanged = await this.checkPackageJsonChanged();
      
      if (packageChanged) {
        this.log('📦 检测到package.json变化，更新依赖...');
        await this.runCommand('npm install --only=production', '安装依赖');
      }

      return packageChanged;
    } catch (error) {
      this.log(`拉取更新失败: ${error.message}`, 'error');
      throw error;
    }
  }

  async checkPackageJsonChanged() {
    try {
      // 检查最近一次提交是否涉及package.json
      const changedFiles = await this.runCommand('git diff --name-only HEAD~1', '检查变化的文件');
      return changedFiles.includes('package.json') || changedFiles.includes('package-lock.json');
    } catch (error) {
      this.log('检查package.json变化失败，假设需要更新依赖', 'warn');
      return true; // 保险起见，假设需要更新
    }
  }

  async restartPM2() {
    try {
      // 检查PM2进程是否存在
      const pm2Status = await this.runCommand('npx pm2 describe multi-exchange-monitor', '检查PM2状态');
      
      if (pm2Status.includes('not found')) {
        this.log('PM2进程不存在，启动新进程');
        await this.runCommand('npm run pm2:start', '启动PM2');
      } else {
        this.log('重启PM2进程...');
        await this.runCommand('npm run pm2:reload', '重启PM2');
      }
      
      // 等待几秒确保进程启动
      await new Promise(resolve => setTimeout(resolve, 3000));
      
      // 验证进程状态
      await this.runCommand('npm run pm2:status', '验证PM2状态');
      
    } catch (error) {
      this.log(`PM2重启失败: ${error.message}`, 'error');
      
      // 尝试强制重启
      try {
        this.log('尝试强制重启PM2...');
        await this.runCommand('npm run pm2:restart', '强制重启PM2');
      } catch (retryError) {
        this.log(`强制重启也失败: ${retryError.message}`, 'error');
        throw retryError;
      }
    }
  }

  async performUpdate() {
    const startTime = new Date();
    this.log('🔄 开始自动更新检查...');

    try {
      // 检查是否有更新
      const hasUpdates = await this.checkGitStatus();
      
      if (!hasUpdates) {
        this.log('✅ 检查完成，无需更新');
        return { updated: false, message: '代码已是最新版本' };
      }

      // 拉取更新
      const packageChanged = await this.pullUpdates();
      
      // 重启PM2
      await this.restartPM2();
      
      const duration = Math.round((new Date() - startTime) / 1000);
      const message = `更新成功完成，耗时${duration}秒${packageChanged ? '（包含依赖更新）' : ''}`;
      
      this.log(`🎉 ${message}`);
      
      return { 
        updated: true, 
        message: message,
        packageChanged: packageChanged,
        duration: duration 
      };

    } catch (error) {
      const duration = Math.round((new Date() - startTime) / 1000);
      const message = `自动更新失败: ${error.message} (耗时${duration}秒)`;
      
      this.log(`❌ ${message}`, 'error');
      
      return { 
        updated: false, 
        error: true,
        message: message,
        duration: duration 
      };
    }
  }

  async run() {
    this.log('🚀 自动更新服务启动');

    // 检查锁文件
    if (this.checkLock()) {
      return;
    }

    try {
      // 创建锁文件
      this.createLock();
      
      // 执行更新检查
      const result = await this.performUpdate();
      
      // 记录结果
      if (result.updated) {
        this.log(`📊 更新统计: ${JSON.stringify(result)}`);
      }
      
      return result;

    } catch (error) {
      this.log(`自动更新过程异常: ${error.message}`, 'error');
      return { updated: false, error: true, message: error.message };
    } finally {
      // 移除锁文件
      this.removeLock();
      this.log('🏁 自动更新检查结束\n');
    }
  }
}

// 如果直接运行此脚本
if (require.main === module) {
  const updater = new AutoUpdater();
  
  updater.run().then((result) => {
    if (result && result.error) {
      process.exit(1);
    }
    process.exit(0);
  }).catch((error) => {
    console.error('自动更新脚本执行失败:', error);
    process.exit(1);
  });
}

module.exports = AutoUpdater;
